package zone.suplog.rpc.rabbitmq.processor;

import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cglib.proxy.Proxy;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import zone.suplog.rpc.rabbitmq.annotation.RabbitRpcConsumer;
import zone.suplog.rpc.rabbitmq.proxy.RabbitProxyInterceptor;
import zone.suplog.rpc.spi.ProxyInterceptor;
import zone.suplog.rpc.spi.RpcConsumerProcessor;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * 消费方需要配置的核心处理器
 */
public class RabbitRpcConsumerProcessor extends RpcConsumerProcessor {

    private Connection connection;
    private String applicationName;
    private String exchange;
    private Long maxConnTimeout;

    private final static String EXCHANGE_PROPERTY_NAME = "spring.suplog-rpc.rabbit-mq.consumer.exchange";
    private final static String MAX_CONN_TIMEOUT_PROPERTY_NAME = "spring.suplog-rpc.rabbit-mq.consumer.max-conn-timeout";
    private final static String APPLICATION_PROPERTY_NAME = "spring.application.name";

    /**
     * 处理器初始化
     */
    @Override
    protected void processInitialization(ApplicationContext applicationContext) {
        Environment environment = applicationContext.getBean(Environment.class);
        super.annotationClass = RabbitRpcConsumer.class;
        this.exchange = environment.getProperty(EXCHANGE_PROPERTY_NAME);
        this.maxConnTimeout = environment.getProperty(MAX_CONN_TIMEOUT_PROPERTY_NAME, Long.class, 5000L);
        this.applicationName = environment.getProperty(APPLICATION_PROPERTY_NAME);
        Assert.hasLength(this.applicationName, "Property '" + APPLICATION_PROPERTY_NAME + "' not found!");
        this.connection = applicationContext.getBean(RabbitTemplate.class).getConnectionFactory().createConnection();
        Assert.notNull(this.connection, "rabbitmq is can't connection!");
    }

    /**
     * 动态代理类处理逻辑，@RabbitRpcConsumer标注的成员属性会赋值为此方法返回的对象
     * 该方法规定了被@RabbitRpcConsumer注解的filed应该执行怎样的操作。
     *
     * @param field @RabbitRpcConsumer注解所标注的Filed
     */
    @Override
    public Object newProxyInstance(Field field) {
        Class<?> consumerClassType = field.getType();
        RabbitRpcConsumer annotation = field.getAnnotation(RabbitRpcConsumer.class);
        ProxyInterceptor proxyInterceptor = new RabbitProxyInterceptor(
                connection,
                consumerClassType,
                StringUtils.hasText(annotation.applicationName()) ? annotation.applicationName() : applicationName,
                StringUtils.hasText(annotation.exchange()) ? annotation.exchange() : exchange,
                Objects.nonNull(maxConnTimeout) ? maxConnTimeout : annotation.maxConnTimeout()
        );
        return Proxy.newProxyInstance(consumerClassType.getClassLoader(), new Class[]{consumerClassType}, proxyInterceptor);
    }
}